package com.xiangxiao.rpan.settings.service.impl;

import com.alibaba.fastjson.JSON;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.util.EnumUtil;
import com.xiangxiao.rpan.settings.constant.GlobalConsts;
import com.xiangxiao.rpan.settings.controller.SiteController;
import com.xiangxiao.rpan.settings.dao.SystemConfigMapper;
import com.xiangxiao.rpan.settings.dto.SystemConfigDTO;
import com.xiangxiao.rpan.settings.entity.SystemConfig;
import com.xiangxiao.rpan.settings.service.SystemConfigService;
import com.xiangxiao.rpan.utils.EnumConvertUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @auther xiangxiao
 * @email 573768011@qq.com
 * @data 2023/6/9 16:46
 */
@Service
public class SystemConfigServiceImpl implements SystemConfigService {
  private static Logger logger = LoggerFactory.getLogger(SiteController.class);
  @Autowired
  private SystemConfigMapper systemConfigMapper;
  @Value("${spring.redis.timeout}")
  private int timeout;
  @Autowired
  private StringRedisTemplate redisTemplate;
  @Autowired
  private SqlSessionFactory sqlSessionFactory;
  private final Class<SystemConfigDTO> systemConfigClazz = SystemConfigDTO.class;

  @Override
  public SystemConfigDTO getSystemConfig() {
    SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
    List<SystemConfig> systemConfigList = systemConfigMapper.findAll();
    String redisKey = GlobalConsts.RPAN_SETTINGS + GlobalConsts.CONFIG_GLOBAL;

    if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey))) {
      systemConfigDTO = JSON.parseObject(redisTemplate.opsForValue().get(redisKey), SystemConfigDTO.class);
      return systemConfigDTO;
    }
    ;
    for (SystemConfig systemConfig : systemConfigList) {
      String key = systemConfig.getName();

      try {
        Field field = systemConfigClazz.getDeclaredField(key);
        field.setAccessible(true);
        String strVal = systemConfig.getValue();
        Class<?> fieldType = field.getType();

        Object convertVal;
        if (EnumUtil.isEnum(fieldType)) {
          convertVal = EnumConvertUtil.convertStrToEnum(fieldType, strVal);
        } else {
          convertVal = Convert.convert(fieldType, strVal);
        }
        field.set(systemConfigDTO, convertVal);
      } catch (NoSuchFieldException | IllegalAccessException | ConvertException e) {
        logger.error("通过反射, 将字段 {} 注入 SystemConfigDTO 时出现异常:", key, e);
      }
    }

    // 获取成功,存入redis,在redis存储未过期之前则直接从redis取用
    redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(systemConfigDTO), timeout, TimeUnit.MILLISECONDS);
    return systemConfigDTO;
  }


  @Override
  public void updateSystemConfig(SystemConfigDTO systemConfigDTO) {
    List<SystemConfig> systemConfigList = new ArrayList<>();
    Field[] fields = systemConfigClazz.getDeclaredFields();
    String redisKey = GlobalConsts.RPAN_SETTINGS + GlobalConsts.CONFIG_GLOBAL;

    for (Field field : fields) {
      String key = field.getName();
      SystemConfig systemConfig = systemConfigMapper.findByName(key);
      if (systemConfig != null) {
        field.setAccessible(true);
        Object val = null;

        try {
          val = field.get(systemConfigDTO);
        } catch (IllegalAccessException e) {
          logger.error("通过反射, 从 SystemConfigDTO 获取字段 {}  时出现异常:", key, e);
        }

        if (val != null) {
          // 如果是枚举类型, 则取 value 值.
          if (EnumUtil.isEnum(val)) {
            val = EnumConvertUtil.convertEnumToStr(val);
          }
          systemConfig.setValue(Convert.toStr(val));
          systemConfigList.add(systemConfig);
        }
      }
    }
    ;
    // 开启批量处理模式BATCH, 关闭自动提交事务的机制,改成全部数据一次性提交,更新完毕后再关闭sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < systemConfigList.size(); i++) {
      systemConfigMapper.updateById(systemConfigList.get(i));
    }
    ;

    // 一次性提交事务
    sqlSession.commit();
    sqlSession.close();
    // 初始化完成后立去重新存一遍redis
    if (StringUtils.isNotBlank(redisTemplate.opsForValue().get(redisKey))) {
      SystemConfigDTO config = getSystemConfig();
      BeanUtils.copyProperties(config, systemConfigDTO);
      redisTemplate.opsForValue().set(redisKey, JSON.toJSONString(config), timeout, TimeUnit.MILLISECONDS);
    }
    ;
    long endTime = System.currentTimeMillis();
    System.out.println("总耗时:" + (endTime - startTime) + "豪秒");
  }

  @Override
  public void resetAdminLoginInfo() {

  }

  @Override
  public String getRsaHexKeyOrGenerate() {
    return null;
  }

  @Override
  public Boolean getSystemIsInstalled() {
    SystemConfigDTO config = getSystemConfig();
    return config.getInstalled();
  }

  @Override
  public String getDomain() {
    return getSystemConfig().getDomain();
  }

  @Override
  public String getFrontDomain() {
    return null;
  }

  @Override
  public String getRealFrontDomain() {
    return null;
  }

  @Override
  public String getForbiddenUrl() {
    return null;
  }
}
